// FreeCell
#ifdef sm
struct {
	// game number; 0 = no game
	uint32_t seed;
	int8_t cards[8][21];
	int8_t top[8]; // top row
	int8_t deck[52];
	uint8_t scroll_top;
	// -1 = null
	// 0..7 = column 0..7
	// 9 = wastebin
	// 10..13 = free cell 1..4
	int8_t cursor, cursor_target;
} fc;
#else
void fc_shuffle() {
	register uint8_t i, j;
	register uint8_t left = 52; // cards left to be chosen in shuffle

	// clear the deck
	for (i = 0; i < 9; i++) {
		for (j = 0; j < 21; j++) {
			sm.fc.cards[i][j] = -1;
		}
	}

	// put unique card in each deck location
	for (i = 0; i < 52; i++) sm.fc.deck[i] = i;

	// shuffle cards
	vcrand_seed = sm.fc.seed;
	for (i = 0; i < 52; i++) {
		j = vcrand() % left;
		sm.fc.cards[i & 7][i >> 3] = sm.fc.deck[j];
		sm.fc.deck[j] = sm.fc.deck[--left];
	}
}

void fc_draw_row(uint8_t y) {
	register uint8_t x, i;
	register int8_t card;

	if (y) {
		fill_scanline(0x0001);
		draw_scanline(y << 3);
	}

	for (i = 1; i < 8; i++) {
		fill_scanline(y ? 0x0001 : 0);
		for (x = 0; x < 8; x++) {
			if (y) {
				card = sm.fc.cards[x][y + sm.fc.scroll_top - 2];
			} else {
				card = sm.fc.top[x];
			}
			if (card >= 0) {
				draw_part((x << 4) + 2, 7 * (card_suit((uint8_t) card) + 1), 134 + i, 7);
				draw_part((x << 4) + 11, card_value((uint8_t) card) << 2, 127 + i, 4);
				if (card_value(card) == 9) draw_part((x << 4) + 9, 2, 129 + i, 2);
			}
			if (y == 7 && sm.fc.cursor == x) draw_part((x << 4) + 5, 0, 135 + i, 7);
		}
		if (sm.fc.cursor >= 10) {
			dm.g.scanline[sm.fc.cursor - 10] = ~dm.g.scanline[sm.fc.cursor - 10];
		}
		draw_scanline((y << 3) + i);
	}
}

void fc_redraw() {
	register uint8_t i;
	for (i = 0; i < 8; i++) fc_draw_row(i);
}

void fc_move_card() {
	if (sm.fc.cursor == -1) {
		// select a column
		// no selecting the wastebin
		if (sm.fc.cursor_target == 9) return;
		// no selecting empty slots
		if (sm.fc.cursor_target >= 10
			&& sm.fc.top[sm.fc.cursor_target - 10] == -1) return;
		if (sm.fc.cursor_target < 8
			&& sm.fc.cards[sm.fc.cursor_target][0] == -1) return;
		sm.fc.cursor = sm.fc.cursor_target;
		fc_draw_row(sm.fc.cursor < 8 ? 7 : 0);
	} else if (sm.fc.cursor == sm.fc.cursor_target) {
		// deselect a column
		sm.fc.cursor = -1;
		fc_redraw();
	} else {
		// move cards
		register uint8_t i, j;
		xdata int8_t* a;
		xdata int8_t* b;
		// from card *a
		if (sm.fc.cursor < 8) {
			// from a column
			for (i = 0; i < 21; i++) {
				if (sm.fc.cards[sm.fc.cursor][i] == -1) break;
			}
			i--;
			a = &sm.fc.cards[sm.fc.cursor][i];
		} else {
			// from a free cell
			a = &sm.fc.top[sm.fc.cursor - 10];
		}
		// to card *b
		if (sm.fc.cursor_target < 8) {
			// to a column
			for (i = 0; i < 21; i++) {
				if (sm.fc.cards[sm.fc.cursor_target][i] == -1) break;
			}
			b = &sm.fc.cards[sm.fc.cursor_target][i];
			if (i > 0 && (card_color(b[-1]) == card_color(*a)
				|| card_value(b[-1]) != card_value(*a) + 1)) return;
		} else if (sm.fc.cursor_target == 9) {
			// to the wastebin
			b = &sm.fc.top[card_suit(*a) | 4];
			if (*b == -1 && card_value(*a) != 0) return;
			if (*b != -1 && card_value(*b) != card_value(*a) - 1) return;
		} else {
			// to a free cell
			b = &sm.fc.top[sm.fc.cursor_target - 10];
			if (*b != -1) return;
		}
		*b = *a;
		*a = -1;
		sm.fc.cursor = -1;
		fc_redraw();
	}
}

void fc_on_keydown(uint8_t key) {
	switch (key) {
	case 0:
		// play the next game
		sm.fc.seed++;
		fc_shuffle();
		sm.fc.scroll_top = 1;
		sm.fc.cursor = -1;
		fc_redraw();
		break;
	case 1:
		if (sm.fc.scroll_top < 15) {
			sm.fc.scroll_top++;
			fc_redraw();
		}
		break;
	case 2:
		if (sm.fc.scroll_top > 1) {
			sm.fc.scroll_top--;
			fc_redraw();
		}
		break;
	case 5: case 6: case 7: case 8:
		sm.fc.cursor_target = key + 5;
		fc_move_card();
		break;
	case 9:
		sm.fc.cursor_target = 9;
		fc_move_card();
		break;
	case 10: case 11:
		sm.fc.cursor_target = key - 4;
		fc_move_card();
		break;
	case 15: case 16: case 17:
		sm.fc.cursor_target = key - 12;
		fc_move_card();
		break;
	case 20: case 21: case 22:
		sm.fc.cursor_target = key - 20;
		fc_move_card();
		break;
	}
	lcd_flush();
}

void fc_on_init(void) {
	lcd_clear_button_text();
	lcd_set_button_text(0, L"N");
	lcd_set_button_text(1, L"\u2193");
	lcd_set_button_text(2, L"\u2191");
	lcd_set_button_text(5, L"01");
	lcd_set_button_text(6, L"02");
	lcd_set_button_text(7, L"03");
	lcd_set_button_text(8, L"04");
	lcd_set_button_text(9, L"9");
	lcd_set_button_text(10, L"7");
	lcd_set_button_text(11, L"8");
	lcd_set_button_text(15, L"4");
	lcd_set_button_text(16, L"5");
	lcd_set_button_text(17, L"6");
	lcd_set_button_text(20, L"1");
	lcd_set_button_text(21, L"2");
	lcd_set_button_text(22, L"3");
	on_keydown = fc_on_keydown;
	lcd_clear();
	lcd_flush();
}
#endif
